//
//  HPZhijiaSwiper.m
//  HPZZTong
//
//  Created by WenJun on 14-6-16.
//  Copyright (c) 2014年 Handpay. All rights reserved.
//

#import "HPZhijiaSwiper.h"
#import "CSwiperController.h"
#import "SwipeInfo.h"
#import "CUtility.h"
#import "CategoryUtil.h"

#define EncryptKey @"enc_key"
#define MAX_MAC_BLOCK_LEN  160


static HPZhijiaSwiper * zhijiaSwiper = nil;

@interface HPZhijiaSwiper()<CSwiperControllerDelegate>
{
    CSwiperController * _cswiper;
}

@end

@implementation HPZhijiaSwiper

+ (id)sharedInstance
{
    if (!zhijiaSwiper)
    {
        zhijiaSwiper = [[super allocWithZone:NULL] init];
    }
    return zhijiaSwiper;
}

- (id)init
{
    self = [super initWithSwiperQueue:dispatch_get_main_queue() wrapperQueue:dispatch_queue_create("zhijiaSwiper", 0)];
    _cswiper = [CSwiperController sharedController];
    return self;
}

- (void)stopOperation{
    [_cswiper setDelegate:nil];
}
- (void)startOperation{
    [_cswiper setDelegate:self];
}
- (NSInvocation *)operationWithSelector:(SEL)selector
{
    NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:[_cswiper methodSignatureForSelector:selector]];
    [invocation setTarget:_cswiper];
    [invocation setSelector:selector];
    return invocation;
}

- (void)getKSN:(SwiperComplete)complete
{
    LOG(@"getKSN");
    if (self.ksn.length > 0)
    {
        ExecuteSwiperBlock(complete, [HPSwiperResult successResult:self.ksn]);
    }
    else if ([_cswiper isDevicePresent] || self.connectState >= SwiperStateDectedDevice)
    {
        [self connectStateChanged:SwiperStateConnecting];
        NSInvocation * operation = [self operationWithSelector:@selector(exchangeAPDU:)];
        NSString * apdu = @"00B0820010";
        [operation setArgument:&apdu atIndex:2];
        [self beginSwiperOperation:operation timeout:10 complete:complete];
    }
    else
    {
        ExecuteSwiperBlock(complete, [HPSwiperResult failResultWithCode:HPSwiperResultNotConnected]);
    }
}

- (void)encryptKeyData:(NSString *)keyData factor:(NSString *)factor complete:(SwiperComplete)complete
{
    [self encyptData:keyData factor:factor type:@"13" complete:complete];
}

- (void)encryptPin:(NSString *)pinStr factor:(NSString *)factor complete:(SwiperComplete)complete
{
    [self encyptData:pinStr factor:factor type:@"14" complete:complete];
}

- (void)encryptMac:(NSString *)mac factor:(NSString *)factor complete:(SwiperComplete)complete
{
    __block BOOL isNeedMulStep = NO;
    int index = 0;
    unsigned char tempApdu[512] = {0};
    char tempStr[512] = {0};
    const char* strByte = [mac UTF8String];
    __block int len = [mac length] + 1;// 必须补80
    
    int needLen = len % 8;
    if (needLen > 0) {
        len += (8 - needLen);
    }
    len += 8; // 最前面强制补8个
    
    tempApdu[index++] = 0x80;
    tempApdu[index++] = 0xFA;
    __block int realLen = len;
    isNeedMulStep = (len > MAX_MAC_BLOCK_LEN);
    if (isNeedMulStep) {
        tempApdu[index++] = 0x07;
        realLen = MAX_MAC_BLOCK_LEN;
    }else{
        tempApdu[index++] = 0x05;
    }
    
    tempApdu[index++] = 0x00;
    tempApdu[index++] = realLen;
    
    index += 8;
    memcpy(tempApdu + index, strByte, [mac length]);
    index += [mac length];
    tempApdu[index] = 0x80;
    hexDecode(tempApdu, realLen + 5, tempStr);
    
    NSString * macApdu = [NSString stringWithUTF8String:tempStr];
    __block SwiperComplete callback = complete;
    __block NSData * tempData = [NSData dataWithBytes:tempApdu length:512];
    [self encyptData:macApdu factor:factor type:@"15" complete:^(HPSwiperResult *swiperResult) {
        if (!isNeedMulStep)
        {
            callback(swiperResult);
        }
        else
        {
            char tempStr2[512] = {0};
            unsigned char tempApdu2[512] = {0};
            memcpy(tempApdu2, tempData.bytes, 512);
            tempApdu2[2] = 0x01;
            tempApdu2[4] = len - realLen;
            
            hexDecode(tempApdu2, 5, tempStr2);
            hexDecode(tempApdu2 + realLen + 5, len - realLen, tempStr2 + 10);
            
            NSInvocation * operation = [self operationWithSelector:@selector(exchangeAPDU:)];
            NSString * apdu = [NSString stringWithUTF8String:tempStr2];
            [operation setArgument:&apdu atIndex:2];
            [self beginSwiperOperation:operation timeout:10 complete:callback];
        }
    }];
}

- (void)encyptData:(NSString *)data factor:(NSString *)factor type:(NSString *)type complete:(SwiperComplete)complete
{
    if ([type isEqualToString:@"13"])
    {
        data = [self packageDesApdu:data];
    }
    else if ([type isEqualToString:@"14"])
    {
        data = [NSString stringWithFormat:@"80FA00000806%@FFFFFFFF", data];
    }
    LOG(@"indata:%@",data);
    NSMutableDictionary * apduDic = [NSMutableDictionary dictionary];
    [apduDic setObject:@[type, [factor substringToIndex:factor.length - 2], data] forKey:EncryptKey];
    NSInvocation * operation = [self operationWithSelector:@selector(batchExchangeAPDU:)];
    [operation setArgument:&apduDic atIndex:2];
    [self beginSwiperOperation:operation timeout:10 complete:complete];
}

//收款功能加密金额特殊处理，快速转账金额直接用关键数据加密
- (void)encyptAmount:(NSString *)amount factor:(NSString *)factor complete:(SwiperComplete)complete
{
    amount = [self packageAmount:amount];
    LOG(@"indata:%@",amount);
    NSMutableDictionary * apduDic = [NSMutableDictionary dictionary];
    [apduDic setObject:@[@"13", [factor substringToIndex:factor.length - 2], amount] forKey:EncryptKey];
    NSInvocation * operation = [self operationWithSelector:@selector(batchExchangeAPDU:)];
    [operation setArgument:&apduDic atIndex:2];
    [self beginSwiperOperation:operation timeout:10 complete:complete];
}

- (NSString *)packageAmount:(NSString *)amount
{
    NSMutableString * result = [NSMutableString stringWithString:amount];
    for (NSInteger index = 0; result.length < 16; index ++)
    {
        [result appendString:@"0"];
    }
    return [NSString stringWithFormat:@"80FA000010%@",result];
}

// 确认金额
- (void)affirmAmount:(NSString *)amount time:(int)time complete:(SwiperComplete)complete
{
    complete([HPSwiperResult successResult:nil]);
}

// 刷卡
- (void)swipe:(int)time factor:(NSString *)factor complete:(SwiperComplete)complete
{
    NSInvocation * operation = [self operationWithSelector:@selector(startCSwiperWithRandomNumber:)];
    [operation setArgument:&factor atIndex:2];
    [self beginSwiperOperation:operation timeout:1000 complete:complete];
}

//// 密码输入
//- (void)inputPwd:(int)time factor:(NSString *)factor complete:(SwiperComplete)complete
//{
//
//}

- (void)onGetFirmwareVersionCompleted:(NSString *)firmwareVersion
{

}
- (void)onGetKsnCompleted:(NSString *)ksn
{
    
}
- (void)onGetBatteryVoltageCompleted:(NSString *)batteryVoltage
{

}
- (void)onWaitingForDevice
{

}
- (void)onWaitingForCardSwipe
{

}
- (void)onCardSwipeDetected
{
    
}
- (void)onDecodingStart
{
    
}
- (void)onInterrupted
{
//    [self operationFinishedWithResult:[HPSwiperResult failResultWithCode:HPSwiperResultInterrupted]];
}
- (void)onIllegalStateError
{
    [self operationFinishedWithResult:[HPSwiperResult failResultWithCode:HPSwiperResultBusy]];
}
- (void)onTimeout
{
    [self operationFinishedWithResult:[HPSwiperResult failResultWithCode:HPSwiperResultTimeout]];
}

- (void)onDecodeError:(CSwiperControllerDecodeResult)decodeResult
{
    LOG(@"onDecodeError:%d",decodeResult);
    [self operationFinishedWithResult:[HPSwiperResult failResultWithCode:HPSwiperResultFail]];
}

- (void)onDecodeCompleted:(NSDictionary *)decodeData
{
    LOG(@"%@",decodeData);
    NSString* maskPan = [decodeData objectForKey:@"maskedPAN"];
    if (![NSString isNilOrEmpty:maskPan])
    {
        HPSwiperResult * result = [HPSwiperResult successResult:[self swipeInfoFromData:decodeData]];
        [self operationFinishedWithResult:result];
    }
    else
    {
         [self operationFinishedWithResult:[HPSwiperResult failResultWithMsg:nil]];
    }
//        encTrack2 = 370FC05C41A2CBA09C357B99C1483FCF2B00000F;
//        encTrack3 = 0000;
//        expiryDate = 3302;
//        formatID = 46;
//        ksn = b629cd3232cd1f9e0100;
//        maskedPAN = 6225220114978588;
//        randomNumber = c165dd052a8fceaa;
//        track1Length = 0;
//        track2Length = 37;
//        track3Length = 0;
}

- (SwipeInfo *)swipeInfoFromData:(NSDictionary *)decodeData
{
    SwipeInfo * swipeInfo = [[SwipeInfo alloc] init];
    NSMutableString * track2Str = [NSMutableString stringWithString:[decodeData objectForKey:@"encTrack2"]];
    while (track2Str.length < 40)
    {
        [track2Str appendString:@"F"];
    }
    swipeInfo.encTrack2 = track2Str;
    swipeInfo.plainAccount = [decodeData objectForKey:@"maskedPAN"];
    swipeInfo.dynamicKey = [[decodeData objectForKey:@"randomNumber"] uppercaseString];
    return swipeInfo;
}
- (void)onError:(int)errorType message:(NSString *)message
{
    LOG(@"onError  ErrorType:%d  message:%@",errorType,message);
    [self operationFinishedWithResult:[HPSwiperResult failResultWithCode:HPSwiperResultFail]];
}
- (void)onNoDeviceDetected
{

}
- (void)onEncryptDataCompleted:(NSDictionary *)encryptDataResponse
{
    
}
- (void)onApduResponseReceived:(NSString *)response
{
    NSString * value = nil;
    if ([self checkResponse:response value:&value])
    {
        if (self.connectState == SwiperStateConnecting)
        {
            self.ksn = [value substringToIndex:20];
            LOG(@"ksn:%@",self.ksn);
            [self connectStateChanged:SwiperStateConnected];
        }
        [self operationFinishedWithResult:[HPSwiperResult successResult:value]];
    }
    else
    {
        [self operationFinishedWithResult:[HPSwiperResult failResultWithMsg:nil]];
    }
}
- (void)onBatchApduResponseReceived:(NSDictionary *)apduResponses
{
    LOG(@"%@",apduResponses);
    if ([[apduResponses allKeys] containsObject:EncryptKey])
    {
        NSString * value = nil;
        if ([self checkResponse:[apduResponses objectForKey:EncryptKey] value:&value])
        {
            LOG(@"value:%@",value);
            [self operationFinishedWithResult:[HPSwiperResult successResult:value]];
        }
        else
        {
            [self operationFinishedWithResult:[HPSwiperResult failResultWithMsg:nil]];
        }
    }
    else
    {
        [self operationFinishedWithResult:[HPSwiperResult successResult:apduResponses]];
    }
}

-(NSString*)packageDesApdu:(NSString*)str{
    int index = 0;
    unsigned char tempApdu[512] = {0};
    char tempStr[512] = {0};
    const char* strByte = [str UTF8String];
    int len = [str length];
    int needLen = len % 8;
    if (needLen > 0) {
        len += (8 - needLen);
    }
    
    tempApdu[index++] = 0x80;
    tempApdu[index++] = 0xFA;
    tempApdu[index++] = 0x00;
    tempApdu[index++] = 0x00;
    tempApdu[index++] = len;
    
    memcpy(tempApdu + index, strByte, [str length]);
    hexDecode(tempApdu, len + index, tempStr);
    return [NSString stringWithUTF8String:tempStr];
}

- (void)onDevicePlugged
{
    [self connectStateChanged:SwiperStateDectedDevice];
}
- (void)onDeviceUnplugged
{
    [self connectStateChanged:SwiperStateNoDeviceDected];
}

- (BOOL)checkResponse:(NSString *)response value:(NSString **)value
{
    if ([response hasSuffix:@"9000"])
    {
        *value = [response substringToIndex:[response length] - 4];
        return YES;
    }
    return NO;
}

- (void)stopSwiper
{
    [_cswiper stopCSwiper];
}

- (BOOL)canInputPin
{
    return NO;
}

@end


//-(NSString*)packageDesApdu:(NSString*)str{
//    int index = 0;
//    unsigned char tempApdu[512];
////    memset(tempApdu, 0xff, 512);
////    NSData * data = [str dataUsingEncoding:NSUTF8StringEncoding];
//    const char* strByte = [str cStringUsingEncoding:NSUTF8StringEncoding];
//    int len = str.length;
//    int needLen = len % 8;
//    if (needLen > 0) {
//        len += (8 - needLen);
//    }
//
//    tempApdu[index++] = 0x80;
//    tempApdu[index++] = 0xFA;
//    tempApdu[index++] = 0x00;
//    tempApdu[index++] = 0x00;
//    tempApdu[index++] = len;
//
//    memcpy(tempApdu + index, strByte, str.length);
//    NSString * result = [[GTMStringEncoding hexStringEncoding] encode:[NSData dataWithBytes:tempApdu length:index + len]];
//    NSLog(@"oldResult:%@",[self packageDesApdu1:str]);
//    return result;
//}